Structurally Conditioned Diffusion: A Generalized Framework for Asymmetric Trajectory Channeling in Labor Markets

Integrating Diffusion Theory with Empirical Analysis of U.S. Skills Data (2015-2023)

R
Diffusion Theory
Labor markets
Author
Affiliation

Roberto Cantillan & Mauricio Bucca

Department of Sociology, PUC

Published

June 30, 2025

1 Introduction: From Employer Decisions to Labor Market Structure

The polarization of the U.S. labor market is not a static feature but an actively reproduced outcome. Its foundations lie in the everyday decisions of employers within firms who determine which skills to demand for the occupations they manage. Foundational studies have demonstrated that the landscape of skills is itself starkly polarized into two distinct domains—a socio-cognitive cluster associated with high wages and a sensory-physical one with low wages (Alabdulkareem et al. 2018)—and that this space has a nested, hierarchical architecture (Hosseinioun et al. 2025). This structural view aligns with recent findings in intergenerational mobility research, which conceptualize occupations not as monolithic categories, but as complex bundles of gradational characteristics, where it is often the underlying traits, rather than the job title itself, that are transmitted across generations (York, Song, and Xie 2025).

Faced with uncertainty about which skills will maximize productivity or prestige, employers often look to the practices of other, similar occupations for guidance. They engage in a process of social learning and imitation. However, we argue this imitation is not random. It is governed by a powerful, yet poorly understood, mechanism of asymmetric filtering: the very nature of a skill—whether it is cognitive or physical—fundamentally alters the pathways it can travel across the occupational status hierarchy. The cumulative result of thousands of these guided, micro-level imitation decisions by employers is a macro-level process we term Asymmetric Trajectory Channeling. This process actively sorts skills into divergent mobility paths—an upward “escalator” for cognitive skills and a “containment field” for physical ones—thus deepening labor market stratification from the demand side.

This study moves beyond describing the consequences of polarization for workers (the supply side) to model the causal mechanisms on the demand side that generate it. By focusing on the rules that guide employer imitation, we explain how structural inequality is not merely a state, but an emergent process reproduced from the ground up.

2 Theoretical Foundations: Modeling Employer Imitation

To formalize the decision-making process of an employer, we draw on and extend modern diffusion theory. While early studies of diffusion often focused on the spread of a single practice (Strang and Soule 1998), contemporary approaches increasingly recognize that diffusion processes are fundamentally heterogeneous and structured. We build on this by proposing a model centered on the employer of a target occupation \(j\) who considers adopting a skill \(k\) by imitating a source occupation \(i\).

We propose that the employer’s decision is guided by three core mechanisms:

Proximity Constraint: An employer is more likely to imitate occupations that are structurally close to their own. As Hedström (1994) argues in his analysis of trade union diffusion, social influence is not random but is channeled through pre-existing networks, for which spatial or structural proximity serves as a powerful proxy. The influence of distant or dissimilar occupations is weaker.

Universal Status Penalty: Imitating skills from occupations with a very different status level—either higher or lower—is generally met with institutional friction. This reflects general barriers, like credentialing or cultural norms, that create a symmetric resistance to mobility across steep hierarchical divides (Strang and Tuma 1993).

Content-Specific Directional Bias: This is our key theoretical innovation. We argue that the decision to imitate is filtered asymmetrically based on the skill’s content. Under conditions of uncertainty, employers often turn to “success stories” as templates for action (Strang and Macy 2001). However, we posit that the perceived value of these success stories is not uniform. Global diffusion studies show that imitation is often driven by prestige, creating strong directional biases (Bail, Brown, and Wimmer 2019). We extend this insight by arguing that this bias is content-specific. The type of skill being considered—whether it is cognitive or physical—determines its perceived appropriateness for upward or downward mobility. This aligns with recent findings that different types of cultural content follow distinct diffusion pathways (Wimmer, Lee, and LaViolette 2025).

While we employ a binary classification (cognitive vs. physical) for analytical clarity, we conceptualize these skill types as capturing broader, multidimensional profiles of occupational characteristics. Research on intergenerational mobility shows that what is often transmitted between generations is not a specific job title but a bundle of underlying traits, values, and work styles (York, Song, and Xie 2025). Thus, when an employer imitates a “skill,” they are effectively adopting a piece of a larger, desirable occupational profile.

This leads to our Generalized Stratified Diffusion Model. The probability of an employer for occupation \(j\) adopting skill \(k\) from occupation \(i\) is:

\[P_{i \to j}^{(k)} = \alpha \cdot \exp(-\lambda d_{ij}) \cdot \exp\left(-\beta|s_j - s_i| - \gamma_k(s_j - s_i)\right)\]

The critical innovation lies in modeling the content-specific directional bias, \(\gamma_k\), as:

\[\gamma_k = \gamma_0 + \delta \cdot \tau_k\]

Here, \(\tau_k\) is the content-type index (e.g., -1 for cognitive, +1 for physical), and our key parameter, \(\delta\), captures the stratification intensity. A significant \(\delta\) would mean that employers systematically favor cognitive skills for upward mobility while containing physical skills, thus providing a direct test of our core mechanism.

The logit transformation yields our estimable model. To properly analyze the temporal dynamics of skill adoption and the interdependencies between events, we situate our model within an event history framework, a method well-suited for adding social structure to diffusion models (Strang 1991):

\[\text{logit } P_{ij}^{(k)} = \theta_0 - \lambda d_{ij} - \beta|s_j - s_i| - \gamma_0(s_j - s_i) - \delta \cdot \tau_k \cdot (s_j - s_i)\]

The stratification interaction term, \(\delta \cdot \tau_k \cdot (s_j - s_i)\), allows us to directly measure the micro-level mechanism of asymmetric filtering that we propose as the engine of macro-level inequality.

3 Empirical Analysis

3.1 Data and Setup

suppressPackageStartupMessages({
  library(kableExtra)
  library(data.table)
  library(ggplot2)
  library(broom)
  library(dplyr)
  library(scales)
  library(lmtest)
  library(knitr)
  library(patchwork)
})

theme_set(theme_minimal() + 
  theme(
    plot.title = element_text(size = rel(1.3), face = "bold", hjust = 0.5),
    plot.subtitle = element_text(size = rel(1.1), hjust = 0.5),
    legend.position = "bottom"
  ))

# --- MODIFICACIÓN ---
# Se comenta la creación de directorios, ya que no se guardará ningún resultado.
# output_dir <- paste0("Stratified_Diffusion_Analysis_", Sys.Date())
# if (!dir.exists(output_dir)) dir.create(output_dir, recursive = TRUE)

comma <- function(x) format(x, big.mark = ",", scientific = FALSE)

3.2 Data Preparation

# --- MODIFICACIÓN ---
# Se define la ruta completa y directa a tu archivo de datos local.
# Asegúrate de que esta ruta sea correcta en tu sistema.
data_path <- "/home/rober/Descargas/all_events_final_enriched.RData"

# Se verifica si el archivo existe en la ruta especificada.
if (file.exists(data_path)) {
  # Si existe, se carga el archivo.
  load(data_path)
  
  # Se asume que el objeto dentro del archivo .RData se llama 'all_events_final_enriched'.
  # Si tiene otro nombre, debes cambiarlo en la línea de abajo.
  if (exists("all_events_final_enriched")) {
    data_for_models <- all_events_final_enriched
  } else {
    # Si el archivo .RData no contiene el objeto esperado, se detiene con un error claro.
    stop("ERROR: El archivo de datos se cargó, pero no contiene el objeto 'all_events_final_enriched'.")
  }
} else {
  # Si el archivo no se encuentra en la ruta, se detiene la ejecución con un error claro.
  stop(paste("ERROR: No se pudo encontrar el archivo de datos en la ruta:", data_path))
}

3.3 Variable Construction

available_cols <- names(data_for_models)

required_mapping <- list(
  diffusion = c("diffusion", "adopt", "adoption", "outcome"),
  structural_distance = c("structural_distance", "dist", "distance", "d_ij"),
  education_diff_abs = c("education_diff_abs", "edu_diff", "status_gap", "educ_diff"),
  skill_group = c("skill_group_for_model", "skill_group", "cluster", "group", "LouvainCluster_2015")
)

column_matches <- list()
for (req_name in names(required_mapping)) {
  possible_names <- required_mapping[[req_name]]
  found_col <- possible_names[possible_names %in% available_cols]
  
  if (length(found_col) > 0) {
    column_matches[[req_name]] <- found_col[1]
  }
}

min_required <- c("diffusion", "structural_distance", "education_diff_abs", "skill_group")
missing_critical <- min_required[!min_required %in% names(column_matches)]

if (length(missing_critical) > 0) {
  stop("Critical columns missing. Please ensure required columns are available.")
}

if (!is.data.table(data_for_models)) {
  data_for_models <- as.data.table(data_for_models)
}

generalized_data <- copy(data_for_models)

diffusion_col <- column_matches$diffusion
distance_col <- column_matches$structural_distance  
education_col <- column_matches$education_diff_abs
skill_group_col <- column_matches$skill_group

generalized_data[, `:=`(
  diffusion = get(diffusion_col),
  d_ij = get(distance_col),
  education_diff_abs = get(education_col),
  skill_group_for_model = get(skill_group_col),
  status_gap_magnitude = abs(get(education_col)),
  status_gap_signed = get(education_col)
)]

unique_skill_groups <- unique(generalized_data$skill_group_for_model)

if ("LouvainC_1" %in% unique_skill_groups && "LouvainC_2" %in% unique_skill_groups) {
  generalized_data[, content_type := case_when(
    skill_group_for_model == "LouvainC_1" ~ "status_enhancing",
    skill_group_for_model == "LouvainC_2" ~ "status_constraining", 
    TRUE ~ "other"
  )]
} else if (length(unique_skill_groups) >= 2) {
  groups_sorted <- sort(unique_skill_groups)
  enhancing_groups <- groups_sorted[1:(length(groups_sorted) %/% 2)]
  constraining_groups <- groups_sorted[(length(groups_sorted) %/% 2 + 1):length(groups_sorted)]
  
  generalized_data[, content_type := case_when(
    skill_group_for_model %in% enhancing_groups ~ "status_enhancing",
    skill_group_for_model %in% constraining_groups ~ "status_constraining",
    TRUE ~ "other"
  )]
} else {
  set.seed(42)
  generalized_data[, content_type := sample(c("status_enhancing", "status_constraining"), 
                                             .N, replace = TRUE, prob = c(0.6, 0.4))]
}

wage_cols <- c("wage_diff_abs", "wage_gap", "wage_difference", "wage_dist")
wage_col_found <- wage_cols[wage_cols %in% names(generalized_data)]

if (length(wage_col_found) > 0) {
  generalized_data[, wage_gap := get(wage_col_found[1])]
} else {
  generalized_data[, wage_gap := 0]
}

generalized_data[, content_type_index := case_when(
  content_type == "status_enhancing" ~ -1,
  content_type == "status_constraining" ~ +1,
  TRUE ~ 0
)]

generalized_data[, stratification_interaction := content_type_index * status_gap_signed]

generalized_data <- generalized_data[content_type %in% c("status_enhancing", "status_constraining")]
generalized_data <- na.omit(generalized_data)

3.4 Descriptive Analysis

desc_stats <- generalized_data[, .(
  N = comma(.N),
  Diffusion_Rate = sprintf("%.1f%%", mean(diffusion, na.rm = TRUE) * 100),
  Mean_Distance = sprintf("%.3f", mean(d_ij, na.rm = TRUE)),
  Mean_Status_Gap = sprintf("%.3f", mean(abs(status_gap_signed), na.rm = TRUE)),
  Upward_Diffusion = sprintf("%.1f%%", mean(diffusion[status_gap_signed > 0], na.rm = TRUE) * 100),
  Downward_Diffusion = sprintf("%.1f%%", mean(diffusion[status_gap_signed < 0], na.rm = TRUE) * 100)
), by = content_type]

kable(desc_stats, 
      caption = "**Table 1: Descriptive Statistics by Content Type**",
      col.names = c("Content Type", "N", "Diffusion Rate", "Mean Distance", 
                    "Mean Status Gap", "Upward Diffusion", "Downward Diffusion")) %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
**Table 1: Descriptive Statistics by Content Type**
Content Type N Diffusion Rate Mean Distance Mean Status Gap Upward Diffusion Downward Diffusion
status_enhancing 353,988 26.8% 0.679 1.934 37.5% 13.6%
status_constraining 318,951 27.0% 0.675 1.806 27.0% 27.1%

Status measured by educational attainment differences between occupations

4 Model Specification and Estimation

4.1 Theoretical Models

formula_homogeneous <- diffusion ~ d_ij + status_gap_magnitude + status_gap_signed + wage_gap
formula_stratified <- diffusion ~ d_ij + status_gap_magnitude + status_gap_signed + 
                                  stratification_interaction + wage_gap

4.2 Model Estimation

model_homogeneous <- glm(formula_homogeneous, data = generalized_data, family = binomial(link = "logit"))
model_stratified <- glm(formula_stratified, data = generalized_data, family = binomial(link = "logit"))

coefs_homogeneous <- coef(model_homogeneous)
coefs_stratified <- coef(model_stratified)

4.3 Parameter Extraction

extract_generalized_parameters <- function(model, model_type) {
  coefs <- coef(model)
  se_coefs <- summary(model)$coefficients[, "Std. Error"]
  
  if (model_type == "homogeneous") {
    return(list(
      alpha_hat = plogis(coefs["(Intercept)"]),
      lambda_hat = -coefs["d_ij"],
      beta_hat = -coefs["status_gap_magnitude"], 
      gamma_0_hat = -coefs["status_gap_signed"],
      delta_hat = 0,
      model_type = "Homogeneous"
    ))
  } else if (model_type == "stratified") {
    return(list(
      alpha_hat = plogis(coefs["(Intercept)"]),
      lambda_hat = -coefs["d_ij"],
      beta_hat = -coefs["status_gap_magnitude"],
      gamma_0_hat = -coefs["status_gap_signed"],
      delta_hat = -coefs["stratification_interaction"],
      delta_se = se_coefs["stratification_interaction"],
      model_type = "Stratified"
    ))
  }
}

params_homogeneous <- extract_generalized_parameters(model_homogeneous, "homogeneous")
params_stratified <- extract_generalized_parameters(model_stratified, "stratified")

5 Statistical Tests and Model Comparison

lr_test <- lrtest(model_homogeneous, model_stratified)
lr_p_value <- lr_test$`Pr(>Chisq)`[2]

aic_comparison <- c(
  Homogeneous = AIC(model_homogeneous),
  Stratified = AIC(model_stratified)
)

bic_comparison <- c(
  Homogeneous = BIC(model_homogeneous),
  Stratified = BIC(model_stratified)
)

mcfadden_homogeneous <- 1 - (model_homogeneous$deviance / model_homogeneous$null.deviance)
mcfadden_stratified <- 1 - (model_stratified$deviance / model_stratified$null.deviance)

model_comparison <- data.frame(
  Model = c("Homogeneous (δ = 0)", "Stratified (δ ≠ 0)"),
  Parameters = c(length(coefs_homogeneous), length(coefs_stratified)),
  McFadden_R2 = sprintf("%.4f", c(mcfadden_homogeneous, mcfadden_stratified)),
  AIC = sprintf("%.1f", c(aic_comparison["Homogeneous"], aic_comparison["Stratified"])),
  BIC = sprintf("%.1f", c(bic_comparison["Homogeneous"], bic_comparison["Stratified"])),
  Delta_hat = c("0 (fixed)", sprintf("%.4f", params_stratified$delta_hat)),
  stringsAsFactors = FALSE
)

kable(model_comparison,
      caption = "**Table 2: Model Comparison - Homogeneous vs Stratified Diffusion**") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE) %>%
  column_spec(6, bold = TRUE)
**Table 2: Model Comparison - Homogeneous vs Stratified Diffusion**
Model Parameters McFadden_R2 AIC BIC Delta_hat
Homogeneous (δ = 0) 5 0.0293 761022.5 761079.6 0 (fixed)
Stratified (δ ≠ 0) 6 0.0613 736001.5 736070.0 0.1814

Likelihood Ratio Test: p-value < 0.001

6 Theoretical Interpretation

gamma_status_enhancing <- params_stratified$gamma_0_hat + params_stratified$delta_hat * (-1)
gamma_status_constraining <- params_stratified$gamma_0_hat + params_stratified$delta_hat * (+1)

interpret_gamma <- function(gamma_value, content_type) {
  if (gamma_value > 0.05) {
    return(paste(content_type, "follows TRICKLE-DOWN pattern"))
  } else if (gamma_value < -0.05) {
    return(paste(content_type, "follows ASPIRATIONAL pattern"))
  } else {
    return(paste(content_type, "shows NEUTRAL pattern"))
  }
}

effect_size <- exp(params_stratified$delta_hat * 2)

6.1 Model Predictions

generate_stratified_predictions <- function(model, data, n_points = 150) {
  baseline_distance <- median(data$d_ij, na.rm = TRUE)
  baseline_status_magnitude <- median(data$status_gap_magnitude, na.rm = TRUE)
  baseline_wage <- median(data$wage_gap, na.rm = TRUE)
  
  status_range <- seq(-4, 4, length.out = n_points)
  
  pred_data_enhancing <- data.frame(
    d_ij = baseline_distance,
    status_gap_magnitude = abs(status_range),
    status_gap_signed = status_range,
    stratification_interaction = -1 * status_range,
    wage_gap = baseline_wage
  )
  
  pred_enhancing <- predict(model, newdata = pred_data_enhancing, type = "response")
  
  pred_data_constraining <- data.frame(
    d_ij = baseline_distance,
    status_gap_magnitude = abs(status_range),
    status_gap_signed = status_range,
    stratification_interaction = +1 * status_range,
    wage_gap = baseline_wage
  )
  
  pred_constraining <- predict(model, newdata = pred_data_constraining, type = "response")
  
  predictions <- rbind(
    data.frame(
      status_gap = status_range,
      probability = pred_enhancing,
      content_type = "Status-Enhancing (Cognitive)",
      tau_value = -1
    ),
    data.frame(
      status_gap = status_range,
      probability = pred_constraining,
      content_type = "Status-Constraining (Physical)", 
      tau_value = +1
    )
  )
  
  return(predictions)
}

stratified_predictions <- generate_stratified_predictions(model_stratified, generalized_data)

6.2 Core Visualization

theory_colors <- c("Status-Enhancing (Cognitive)" = "#E69F00", "Status-Constraining (Physical)" = "#56B4E9")

p_main <- ggplot(stratified_predictions, aes(x = status_gap, y = probability, color = content_type)) +
  geom_line(size = 1.8, alpha = 0.9) +
  geom_vline(xintercept = 0, linetype = "dashed", alpha = 0.7, color = "gray50") +
  scale_color_manual(values = theory_colors, name = "Skill Type") +
  scale_y_continuous(labels = percent_format(accuracy = 1)) +
  annotate("text", x = -2.5, y = max(stratified_predictions$probability) * 0.85, 
           label = "← TRICKLE-DOWN\n(High → Low Status)", 
           hjust = 0.5, size = 4, color = "gray30", fontface = "bold") +
  annotate("text", x = 2.5, y = max(stratified_predictions$probability) * 0.85, 
           label = "ASPIRATIONAL →\n(Low → High Status)", 
           hjust = 0.5, size = 4, color = "gray30", fontface = "bold") +
  labs(
    title = "Asymmetric Trajectory Channeling in U.S. Labor Markets",
    subtitle = sprintf("δ = %.4f: Stratification Intensity Parameter (p < 0.001)", params_stratified$delta_hat),
    x = "Educational Status Gap (s_j - s_i)",
    y = "Predicted Skill Diffusion Probability", 
    caption = "Note: Status measured by educational attainment differences between occupations."
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(size = rel(1.4), face = "bold", hjust = 0.5),
    plot.subtitle = element_text(size = rel(1.1), hjust = 0.5),
    legend.position = "bottom",
    legend.title = element_text(face = "bold"),
    axis.title = element_text(face = "bold"),
    plot.caption = element_text(size = rel(0.8), color = "gray30")
  )

print(p_main)

# --- MODIFICACIÓN ---
# Se comenta la línea que guarda el gráfico para no crear archivos locales.
# ggsave(file.path(output_dir, "asymmetric_trajectory_channeling.png"), 
#        p_main, width = 14, height = 10, dpi = 300, bg = "white")

Figure 1: Asymmetric Trajectory Channeling in U.S. Labor Markets

Note: Status measured by educational attainment differences between occupations.

6.3 Decomposition Analysis

generate_penalty_predictions <- function(model, data, n_points = 150) {
  baseline_distance <- median(data$d_ij, na.rm = TRUE)
  baseline_wage <- median(data$wage_gap, na.rm = TRUE)
  
  status_magnitude_range <- seq(0, 4, length.out = n_points)
  
  pred_data_penalty <- data.frame(
    d_ij = baseline_distance,
    status_gap_magnitude = status_magnitude_range,
    status_gap_signed = 0,
    stratification_interaction = 0,
    wage_gap = baseline_wage
  )
  
  penalty_predictions <- predict(model, newdata = pred_data_penalty, type = "response")
  
  penalty_effects <- data.frame(
    status_gap = status_magnitude_range,
    probability = penalty_predictions,
    effect_type = "Universal Status Penalty (β)"
  )
  
  return(penalty_effects)
}

penalty_data <- generate_penalty_predictions(model_stratified, generalized_data)

p_penalty <- ggplot(penalty_data, aes(x = status_gap, y = probability)) +
  geom_line(color = "#2C3E50", size = 1.5, alpha = 0.9) +
  scale_y_continuous(labels = percent_format(accuracy = 1)) +
  labs(
    title = "Universal Status Penalty (β parameter)",
    subtitle = "Symmetric resistance to status boundary crossing",
    x = "Status Gap Magnitude |s_j - s_i|",
    y = "Predicted Diffusion Probability"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(size = rel(1.2), face = "bold", hjust = 0.5),
    plot.subtitle = element_text(size = rel(1.0), hjust = 0.5)
  )

p_content_specific <- ggplot(stratified_predictions, aes(x = status_gap, y = probability, color = content_type)) +
  geom_line(size = 1.5, alpha = 0.9) +
  geom_vline(xintercept = 0, linetype = "dashed", alpha = 0.7, color = "gray50") +
  scale_color_manual(values = theory_colors, name = "Skill Type") +
  scale_y_continuous(labels = percent_format(accuracy = 1)) +
  labs(
    title = "Content-Specific Directional Bias (γ_k parameter)",
    subtitle = "Asymmetric filtering by skill type",
    x = "Educational Status Gap (s_j - s_i)",
    y = "Predicted Diffusion Probability"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(size = rel(1.2), face = "bold", hjust = 0.5),
    plot.subtitle = element_text(size = rel(1.0), hjust = 0.5),
    legend.position = "bottom"
  )

combined_plot <- p_penalty / p_content_specific + 
  plot_annotation(
    title = "Decomposition: Universal vs Content-Specific Diffusion Effects",
    subtitle = "Evidence for Dual Filtering Mechanisms in Skill Mobility",
    theme = theme(
      plot.title = element_text(size = rel(1.3), face = "bold", hjust = 0.5),
      plot.subtitle = element_text(size = rel(1.1), hjust = 0.5)
    )
  )

print(combined_plot)

# --- MODIFICACIÓN ---
# Se comenta la línea que guarda el gráfico combinado.
# ggsave(file.path(output_dir, "decomposition_universal_vs_content_specific.png"), 
#        combined_plot, width = 12, height = 10, dpi = 300, bg = "white")

7 Discussion: The Stratification Engine

Our empirical results provide robust evidence that the process of Asymmetric Trajectory Channeling emerges from the micro-level decisions of employers. The significant δ parameter confirms that content-specific directional bias is a powerful mechanism of labor market stratification. This mechanism generates distinct mobility regimes for different skill types:

Escalator Dynamics for Cognitive Skills: The aspirational pattern for cognitive skills shows they are readily adopted upwards in the status hierarchy. This aligns with the view of occupations as multidimensional bundles of traits (York et al., 2024). Cognitive skills likely correspond to abstract, transferable characteristics like ‘problem-solving’, which are valuable across many high-status contexts, making them appear as “nested” capabilities that signal potential for further growth.

Containment Dynamics for Physical Skills: The trickle-down pattern for physical skills shows they face a “glass ceiling.” These skills map onto more context-specific occupational characteristics, limiting their perceived value and thus their diffusion pathways. Employers perceive them as “un-nested”, constraining them to lower-status occupational clusters.

This reframes stratification as an active, demand-side process. Inequality is not just a result of workers’ attributes but is continuously reproduced by the filtering rules employers use when they imitate skill requirements. The destiny of a worker is thus tied not just to the skills they possess, but to the mobility regime those skills inhabit.

# --- MODIFICACIÓN ---
# Se comenta todo el bloque para no guardar el archivo .rds con los resultados.

# stratified_diffusion_results <- list(
#   data = generalized_data,
#   models = list(
#     homogeneous = model_homogeneous,
#     stratified = model_stratified
#   ),
#   parameters = list(
#     homogeneous = params_homogeneous,
#     stratified = params_stratified
#   ),
#   predictions = stratified_predictions,
#   penalty_effects = penalty_data,
#   statistical_tests = list(
#     lr_test = lr_test,
#     aic_comparison = aic_comparison,
#     bic_comparison = bic_comparison
#   ),
#   interpretation = list(
#     gamma_cognitive = gamma_status_enhancing,
#     gamma_physical = gamma_status_constraining,
#     stratification_intensity = params_stratified$delta_hat,
#     effect_size = effect_size
#   ),
#   plots = list(
#     main_trajectory_channeling = p_main,
#     decomposition = combined_plot
#   )
# )
# 
# saveRDS(stratified_diffusion_results, file.path(output_dir, "stratified_diffusion_complete_results.rds"))

8 Conclusions and Future Directions

This study makes several key contributions. Theoretically, we specify a micro-founded model of employer imitation and introduce the Generalized Stratified Diffusion Model to test its core mechanism: content-specific filtering, captured by the δ parameter. Empirically, our analysis provides robust evidence for this mechanism and the resulting macro-level process of Asymmetric Trajectory Channeling.

This demand-side perspective has significant policy implications, shifting the focus from simply training workers (supply-side) to transforming the institutional rules and biases that govern how employers value and adopt skills (demand-side).

Future research should examine the temporal dynamics of these diffusion patterns, test our framework in different institutional contexts, and further unpack the specific organizational routines and cognitive biases that underlie employers’ imitative decisions. It would also be fruitful to explore how the stratification mechanisms we identify interact with other network processes, such as the “Trojan horse” mechanisms that have been shown to reduce segregation in other contexts (Arvidsson, Collet, and Hedström 2021). Our research demonstrates that labor market polarization is an actively maintained outcome of structured diffusion processes. Understanding and reshaping these pathways is a critical frontier for addressing contemporary economic inequality.

Data Availability Statement: O*NET data is publicly available from the U.S. Department of Labor.

References

Alabdulkareem, Ahmad, Morgan R. Frank, Lijun Sun, Bedoor AlShebli, César Hidalgo, and Iyad Rahwan. 2018. “Unpacking the Polarization of Workplace Skills.” Science Advances 4 (7): eaao6030. https://doi.org/10.1126/sciadv.aao6030.
Arvidsson, M., F. Collet, and P. Hedström. 2021. “The Trojan-Horse Mechanism: How Networks Reduce Gender Segregation.” Science Advances 7 (16): eabf6730. https://doi.org/10.1126/sciadv.abf6730.
Bail, Christopher A., Taylor W. Brown, and Andreas Wimmer. 2019. “Prestige, Proximity, and Prejudice: How Google Search Terms Diffuse Across the World.” American Journal of Sociology 124 (5): 1496–1548. https://doi.org/10.1086/702007.
Hedström, Peter. 1994. “Contagious Collectivities: On the Spatial Diffusion of Swedish Trade Unions, 1890-1940.” American Journal of Sociology 99 (5): 1157–79. https://doi.org/10.1086/230408.
Hosseinioun, Moh, Frank Neffke, Letian Zhang, and Hyejin Youn. 2025. “Skill Dependencies Uncover Nested Human Capital.” Nature Human Behaviour, February. https://doi.org/10.1038/s41562-024-02093-2.
Strang, David. 1991. “Adding Social Structure to Diffusion Models: An Event History Framework.” Sociological Methods & Research 19 (3): 324–53. https://doi.org/10.1177/0049124191019003003.
Strang, David, and Michael W. Macy. 2001. “In Search of Excellence: Fads, Success Stories, and Adaptive Emulation.” American Journal of Sociology 107 (1): 147–82. https://doi.org/10.1086/323039.
Strang, David, and Sarah A. Soule. 1998. “Diffusion in Organizations and Social Movements: From Hybrid Corn to Poison Pills.” Annual Review of Sociology 24 (1): 265–90. https://doi.org/10.1146/annurev.soc.24.1.265.
Strang, David, and Nancy Brandon Tuma. 1993. “Spatial and Temporal Heterogeneity in Diffusion.” American Journal of Sociology 99 (3): 614–39. https://doi.org/10.1086/230318.
Wimmer, Andreas, Seungwon Lee, and Jack LaViolette. 2025. “Diffusion Through Multiple Domains: The Spread of Romantic Nationalism Across Europe, 1770–1930.” American Journal of Sociology 130 (4): 931–75. https://doi.org/10.1086/732796.
York, Hunter, Xi Song, and Yu Xie. 2025. “Gradationalism Revisited: Intergenerational Occupational Mobility Along Axes of Occupational Characteristics.” American Journal of Sociology 130 (4): 976–1027. https://doi.org/10.1086/733122.